﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using HeapSpecSupport;
using SimpleIR;

namespace Evaluator.EvalState
{
	internal sealed class EDelegateObject : EBuiltinObject
	{
		internal IRInvokeIdentity InvokeTargetIdentity;

		internal readonly IRMemberField TargetObjField;
		internal readonly IRMemberField InvokeNameField;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{
			Contract.Invariant(this.TargetObjField != null);
			Contract.Invariant(this.InvokeNameField != null);
		}

		/// <summary>
		/// This constructor takes ownership of the <c>fvalues</c> array and other arguments.
		/// </summary>
		private EDelegateObject(int address, IRLambdaType tt, AllocRecord alloc, BAPLayoutMap fvalues, IRInvokeIdentity invtrgt, IRMemberField tf, IRMemberField mf)
			: base(address, tt, alloc, fvalues)
		{
			Contract.Requires(tf != null);
			Contract.Requires(mf != null);

			this.InvokeTargetIdentity = invtrgt;

			this.TargetObjField = tf;
			this.InvokeNameField = mf;
		}

		/// <summary>
		/// Allocate and set all the fields to the default values for an delegate type value.
		/// </summary>
		internal static EDelegateObject CreateDelegateValue(int address, IRLambdaType tt, ulong time, long line)
		{
			Contract.Requires(tt != null);
			
			BAPLayoutMap fve = new BAPLayoutMap(tt.TypeDescription.AllTerminalAccessPaths, time, line);

			IRMemberField tf = tt.TypeDescription.GetFieldWithNameDefIn("target");
			IRMemberField mf = tt.TypeDescription.GetFieldWithNameDefIn("method");
			AllocRecord alloc = new AllocRecord(time, line);

			return new EDelegateObject(address, tt, alloc, fve, null, tf, mf);
		}

		public override string ToString()
		{
			return "Lambda: " + this.InvokeTargetIdentity.ToString();
		}
	}
}
